package com.apes.scm.voucher.service.builder;

import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.InventoryConsign;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.service.InventoryConsignService;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.account.method.Batch;
import com.apes.scm.account.method.BatchMethod;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static java.lang.Math.abs;

/**
 * 功能：销售退回凭证构造器
 *
 * @author xul
 * @create 2018-10-18 9:26
 */
@Component
public class SaleReturnVoucherBuilder extends AbstractVoucherBuilder {

    @Autowired
    private InventoryConsignService inventoryConsignService;

    @Autowired
    private InventoryService inventoryService;

    public SaleReturnVoucherBuilder() {
        this.voucherType = VoucherType.CUSTOMER_SALE;
        this.BusinessTypes = new String[]{BusinessType.SALE_RETURN};
    }

    /**
     * 功能：保存凭证
     *
     * @param voucher
     */
    @Override
    public Voucher create(Voucher voucher) {
        voucher.setReturned(true);

        if (!("Customer".equals(voucher.getPartner().getRole().getId()))) {
            throw new RuntimeException("销售凭证请指定客户角色的合作伙伴[" + voucher.getPartner().getId() + "]!");
        }

        /**保存凭证**/
        voucher = save(voucher);

        /**成本核算/价值评估**/
        costing(voucher);

        /**跨公司/公司间交易**/
        crossCompanyTransaction(voucher);

        /**减少客户寄售库存**/
        customerReturn(voucher);

        /**账单：用于跨公司内部交易记帐**/
        if (voucher.isInvoiced() && voucher.getInventoryMode().equals(InventoryMode.IM_OWN)) {
            invoiced(voucher);
        }

        return voucher;
    }

    /**
     * 减少客户寄售库存
     */
    private void customerReturn(Voucher voucher) {
        if (!voucher.getInventoryMode().equals(InventoryMode.IM_CONSIGN)) return;
        Set<InventoryConsign> inventoryConsigns = new HashSet<>();
        voucher.getVoucherItems().stream().forEach(vi -> {
            new BatchMethod<Batch>() {
                @Override
                public Iterable<Batch> wrap() {
                    List<InventoryConsign> inventoryConsigns = inventoryConsignService.findInventoryConsignForOrder(
                            voucher.getCompany(), getCustomer(voucher.getPartner()), vi.getProduct(), vi.computeBasePrice());
                    return inventoryConsignService.wrapBatch(inventoryConsigns, vi.baseUom(), ic -> ic.getBalanceQty() - ic.getFrostBalanceQty());
                }

                @Override
                public void succeed(Batch batch, double increment) {
                    InventoryConsign inventoryConsign = (InventoryConsign) batch.getEntity();
                    double qty = vi.baseUom().computeQty(increment, inventoryConsign.getUom(), true);
                    inventoryConsign.changeReturnQty(abs(qty));
                    inventoryConsign.changeBalanceQty(-1 * qty);
                    inventoryConsigns.add(inventoryConsign);

                    InventoryBatch inventoryBatch = inventoryConsign.getInventoryBatch();
                    if (inventoryBatch != null) {
                        double changeQty = vi.baseUom().computeQty(increment, inventoryBatch.getUom(), true);
                        new BatchMethod<Batch>() {
                            @Override
                            public Iterable<Batch> wrap() {
                                List<InventoryBatch> inventories = new ArrayList<>();
                                inventories.add(inventoryBatch);
                                List<Long> batchNumbers = inventories.stream().map(inventoryBatch -> inventoryBatch.getBatchNumber()).collect(Collectors.toList());
                                inventories = inventoryService.findAllByBatchNumber(batchNumbers, inventory -> inventory.getFrostQty());
                                return inventoryService.wrapBatch(inventories, vi.baseUom(), inventory -> inventory.getFrostQty());
                            }

                            @Override
                            public void succeed(Batch batch, double increment) {
                                InventoryBatch inventoryBatch = (InventoryBatch) batch.getEntity();
                                inventoryService.changeFrostQty(inventoryBatch, vi.baseUom(), -1 * abs(increment), voucher.getCompany(),
                                        voucher.getInnerBusinessType(), voucher.getId(), String.valueOf(vi.getId()), "客户寄售库存解冻批次！");
                            }

                            @Override
                            public void error(double surplus) {
                                throw new RuntimeException("商品：["+vi.getProduct().getId()+"]" + vi.getProduct().getName() + " 冻结数量少 " + surplus + vi.baseUom().getName() + "！");
                            }
                        }.execute(abs(changeQty));

                    }
                }

                @Override
                public void error(double surplus) {
                    throw new RuntimeException("商品：["+vi.getProduct().getId()+"]" + vi.getProduct().getName() + " 寄售库存数量少 " + surplus + vi.getUom().getName() + "！");
                }
            }.execute(abs(vi.computeBaseQty()));
        });
        inventoryConsignService.returns(inventoryConsigns);
    }
}
